热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CS20SI|Lecture4StructureyourTensorFlowmodel

前面一节中使用TensorFlow实现了简单的线性回归和逻辑斯谛回归。然而,复杂的模型是需要更好的总体设计,否则我们的模型将会变得非常混乱和很难调试。在接下来的两章中,将介绍如何有效地构建结构化

前面一节中使用TensorFlow实现了简单的线性回归和逻辑斯谛回归。然而,复杂的模型是需要更好的总体设计,否则我们的模型将会变得非常混乱和很难调试。在接下来的两章中,将介绍如何有效地构建结构化的模型。
本节将通过word2vec实例讲解。涉及到的部分NLP内容由于我本人理解有限所以就没有详细介绍,建议查阅相关资料
本文只记录了部分代码,完整代码请查看课程GitHub

Agenda
  • Overall structure of a model in TensorFlow
  • word2vec
  • Name scope
  • Embedding visualization

Overall structure of a model in TensorFlow

Phase 1: Assemble graph

  1. 定义输入输出的的容器placecholder
  2. 定义网络权值参数
  3. 定义推理模型
  4. 定义损失函数
  5. 定义优化器

Phase 2: Compute

Created with Raphaël 2.1.0 初始化模型参数 输入训练数据 在训练数据上执行推理 计算损失 调整模型参数

Word Embedding

通过词嵌入可以得到词语之间语义(semantic)上的关系
下图是使用TensorBoard中的t-SNE技术对词嵌入的结果进行可视化,可以看到和单词can语义相近的词语也均为情态动词。
词嵌入可视化

word2vec

wrod2vec是词嵌入的一种方式,具体内容可以参阅论文
Distributed Representations of Words and Phrases and their Compositionality
Efficient Estimation of Word Representations in Vector Space
我们需要词语的向量表示来输入到神经网络中进行后续的相关工作。
本章中使用skip-gram model构建word2vec。
Word2Vec Tutorial - The Skip-Gram Model
在skip-gram模型中,通过训练一个单隐层的神经网络来实现这个任务。但是我们关注的不是网络的输出,而是隐藏层的权重矩阵,这个权重矩阵就是我们需要的word vectorembedding matrix
在这个任务中,我们需要实现给定一句话中的中心词语(center word)来预测该词语附近的词语(上下文,语境)。
给定一个特定的词语,查找附近的词语并随机选择一个。神经网络会输出单词表中每一个词语出现在选定词语附近的概率。

Softmax, Negative Sampling, and Noise Contrastive Estimatio

这一小节主要介绍了word2vec的几种训练优化方式。
在CS224N(一门关于自然语言处理与深度学习的课程)中,讲过了两种训练方式:hierachical softmax(层次softmax)和 negative sampling。由于计算softmat函数需要进行归一化,这涉及了遍历词汇表中的所有单词,计算开销大,所以排除softmax的训练方式。在CS224N中,使用的是negative sampling + skip-gram model实现的word2vec。
Negative Sampling,负采样,是采样方法的一种,通过对样本进行采样来实现对原样本的近似。其他的还有importance sampling和target sampling。
个人理解NegativeSampling方法是通过在单词表中抽样部分单词作为负样本来代替总体,这样在计算损失的时候,只计算在这些抽样出的样本上的损失,而避免了遍历整个单词表,由于每次抽样都是随机的。多次抽样后的结果可以近似总体分布。每次只更新正确词语和抽样出的错误词语对应的权重。这种方法很适合当样本类别数量非常多的时候使用。TF里可以使用tf​.​nn​.​nce_loss实现。
Negative Sampling实际上是Noise Contrastive Estimation(NCE噪声对比估计)的一种简化版本,由于NCE还没有看,这里直接贴出一个简单解释

negative sampling makes certain assumption about the number of noise samples to generate (k) and the distribution of noise samples (Q) (negative sampling assumes that kQ(w) = 1) to simplify computation

相关文章
​On word embeddings - Part 2: Approximating the Softmax -Sebastian Rudder
NotesonNoiseContrastiveEstimationandNegativeSampling
Mikolov等在论文Distributed Representations of Words and Phrases and their Compositionality中提到使用Skip-gram model相比于复杂的hierarchical softmax来说能够更快的训练word2vec并在频繁出现的单词上获得更好的向量表示。
当噪音样本数量增加时,NCE具有negative sampling所缺乏的理论保证。Mnih and Teh(2012)说明了噪音样本数量取25的时候可以获得与常规softmax方法近似的表现,而训练速度却加快了约45倍。
在本章中,由于NCE具有理论保证,使用NCE方法实现word2vec。
最后注意,基于采样的方法只在训练过程中有用,在实际预测的时候,仍然需要用完整的softmax来获得归一化的概率。

About the Dataset

本节使用的数据集合是2006年3月3日的经过数据清洗的英语维基百科语料库中的前100MB部分。
然而100MB的训练数据其实并不能很好的训练出词向量,但是还是可以观察出一些有趣的现象。简单分词后大约有17,005,207个单词。
想要获得更好的结果,可以使用Matt Mahoney’s website​上的维基百科的dataset enwik9 的前10^9bytes 语料。

实战word2vec

Phase 1: Assemble the graph

  1. Define placeholders for input and output
    输入为中心词,输出为目标词(上下文中的)。这里直接使用单词下标而不是用one-hot 向量。我们对预料库进行预处理使得每一个单词都对应一个唯一的索引下标。所有输入输出均为一个标量数字scalar。

    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​])
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​])

  2. Define the weight(embedding matrix)
    我们使用一个[VOCAB_SIZE,EMBED_SIZE]的矩阵来表示,该矩阵的每一行就是词语表中每个单词的词向量,每个词向量的大小为EMBED_SIZE。权重矩阵初始化为-1到1的均匀分布。
    embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​))

  3. Inference(计算图的前向计算)
    我们需要获得输入单词的词向量表示。事实上,对于一个独热编码后的单词输入来说,其向量与嵌入矩阵的乘积结果就是对应嵌入矩阵的某一行。也就是说,这里其实不需要做矩阵乘法运算,只需要选取对应的行即可。TF封装了tf​.​nn​.​embedding_lookup根据获取指定索引对应的词向量表示。
    这里写图片描述
    tf​.​nn​.​embedding_lookup​(​params​,​ ids​,​ partition_strategy​=​'mod'​,​ name​=​None​, validate_indices​=​True​,​ max_norm​=​None)
    embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words)
  4. Define the loss function
    TF封装好了nce_loss
    tf​.​nn​.​nce_loss​(​weights​,​ biases​,​ labels​,​ inputs​,​ num_sampled​,​ num_classes​,​ num_true​=​1​, sampled_values​=​None​,​ remove_accidental_hits​=​False​,​ partition_strategy​=​'mod'​, name​=​'nce_loss')
    num_sampled参数是训练时用来作负样本的噪声单词的数量。
    具体实现

    nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​])) 
    loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​,  biases​=​nce_bias​,  labels​=​target_words​,  inputs​=​embed​,  num_sampled​=​NUM_SAMPLED​,  num_classes​=​VOCAB_SIZE​)) 
  5. Define optimizer
    optimizer ​=​ tf​.​train​.​GradientDescentOptimizer​(​LEARNING_RATE​).​minimize​(​loss)

Phase 2: Execute the computation

with​ tf​.​Session​()​ ​as​ sess:     
    sess​.​run​(​tf​.​global_variables_initializer​()) 
    average_loss ​=​ ​0.0     ​
    batch ​=​ batch_gen​.​next​()         
    loss_batch​,​ _ ​=​ sess​.​run​([​loss​,​ optimizer​], feed_dict​={​center_words​:​ batch​[​0​],​ target_words​:​ batch​[​1​]})
    average_loss ​+=​ loss_batch         ​
    if​ ​(​index ​+​ ​1​)​ ​%​ ​2000​ ​==​ ​0:             
        ​print​(​'Average loss at step {}: {:5.1f}'​.​format​(​index ​+​ ​1​,average_loss ​/​ ​(​index ​+​ ​1​))) 

Name Scope

使用TensorBoard查看现在的网络结构
这里写图片描述
现在的结构图可读性很差,结点遍布在各个地方。TensorBoard不知道哪些结点具有相似的功能而应该被聚集在一起。如我们可以把与input/output相关的ops联系起来,与NCE loss相关的ops联系起来。TensorFlow提供了一种方式实现。

with​ tf​.​name_scope​(​name_of_that_scope​): 
    # declare op_1 
    # declare op_2 
    # ... 

举例来说,我们计算图可以分成3个op块,”Data”,”embed”,”NCE_LOSS”,

with​ tf​.​name_scope​(​'data'​):         
    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​],​ name​=​'center_words')         
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​,​ ​1​],​ name​=​'target_words') 

with​ tf​.​name_scope​(​'embed'​):     
    embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​), name​=​'embed_matrix') 
with​ tf​.​name_scope​(​'loss'​):     
    embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words​,​ name​=​'embed')     
    nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​]),​ name​=​'nce_bias')     
    loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​, biases​=​nce_bias​,​ labels​=​target_words​,​ inputs​=​embed​, num_sampled​=​NUM_SAMPLED​,​ num_classes​=​VOCAB_SIZE​), name​=​'loss') 

看起来命名域embed似乎只有一个结点embed_matrix。事实上,它含有两个结点tf.Variabletf.random_uniform,使用上述代码再查看计算图,更加清晰易读。点击每一个op块的右上角的+号可以查看该块包含的ops
这里写图片描述
计算图中的实线表示数据流动的边。虚线表示依赖控制的边。如图中的loss依赖于init。控制依赖可以使用第2章讲的tf.Graph.control_dependencies(control_inputs)实现。
图例
这里写图片描述
完整流程

# Step 1: define the placeholders for input and output 
with​ tf​.​name_scope​(​"data"​):     
    center_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​],​ name​=​'center_words')     
    target_words ​=​ tf​.​placeholder​(​tf​.​int32​,​ shape​=[​BATCH_SIZE​,​ ​1​],​ name​=​'target_words') 
with​ tf​.​device​(​'/cpu:0'​):     ​
    with​ tf​.​name_scope​(​"embed"​):         ​
        # Step 2: define weights. In word2vec, it's actually the weights that we care about
        embed_matrix ​=​ tf​.​Variable​(​tf​.​random_uniform​([​VOCAB_SIZE​,​ EMBED_SIZE​],​ ​-​1.0​,​ ​1.0​), name​=​'embed_matrix') 
     ​# Step 3 + 4: define the inference + the loss function with​ tf​.​name_scope​(​"loss"​): 
         ​# Step 3: define the inference
         embed ​=​ tf​.​nn​.​embedding_lookup​(​embed_matrix​,​ center_words​,​ name​=​'embed') 
         ​# Step 4: construct variables for NCE loss
         nce_weight ​=​ tf​.​Variable​(​tf​.​truncated_normal​([​VOCAB_SIZE​,​ EMBED_SIZE​],stddev​=​1.0​ ​/​ math​.​sqrt​(​EMBED_SIZE​)), name​=​'nce_weight')         
         nce_bias ​=​ tf​.​Variable​(​tf​.​zeros​([​VOCAB_SIZE​]),​ name​=​'nce_bias') 
         ​# define loss function to be NCE loss function
         loss ​=​ tf​.​reduce_mean​(​tf​.​nn​.​nce_loss​(​weights​=​nce_weight​,biases​=​nce_bias​,​ labels​=​target_words​, inputs​=​embed​,num_sampled​=​NUM_SAMPLED​, num_classes​=​VOCAB_SIZE​),​ name​=​'loss') 
     ​# Step 5: define optimizer 
     optimizer ​=​ tf​.​train​.​GradientDescentOptimizer​(​LEARNING_RATE​).​minimize​(​loss)

面向对象编程

为了提升代码的重用性,使用面向对象的思想

class​ ​SkipGramModel:""" Build the graph for word2vec model """def__init__(​self​,​ ​params​):pass 
    def_create_placeholders(​self​):""" Step 1: define the placeholders for input and output """passdef_create_embedding(​self​):""" Step 2: define weights. In word2vec, it's actually the weights that we care about """passdef_create_loss(​self​):""" Step 3 + 4: define the inference + the loss function """pass 
    def_create_optimizer(​self​):""" Step 5: define optimizer """pass

t-SNE

t​-​distributed stochastic neighbor embedding ​(​t​-​SNE​)​ ​is​ a machine learning algorithm ​for dimensionality reduction developed ​by​ ​Geoffrey​ ​Hinton​ ​and​ ​Laurens​ van der ​Maaten​.​ ​It​ ​is​ a nonlinear dimensionality reduction technique that ​is​ particularly well​-​suited ​for​ embedding high​-​dimensional data ​into​ a space of two ​or​ three dimensions​,​ which can ​then​ be visualized in​ a scatter plot​.​ ​Specifically​,​ it models each high​-​dimensional ​object​ ​by​ a two​-​ ​or three​-​dimensional point ​in​ such a way that similar objects are modeled ​by​ nearby points ​and dissimilar objects are modeled ​by​ distant points​.
The​ t​-​SNE algorithm comprises two main stages​.​ ​First​,​ t​-​SNE constructs a probability distribution over pairs of high​-​dimensional objects ​in​ such a way that similar objects have a high probability of being picked​,​ whilst dissimilar points have an extremely small probability of being picked​.​ ​Second​,​ t​-​SNE defines a similar probability distribution over the points ​in​ the low​-​dimensional map​,​ ​and​ it minimizes the ​Kullback​–​Leibler​ divergence between the two distributions ​with​ respect to the locations of the points ​in​ the map​.​ ​Note
that whilst the original algorithm uses the ​Euclidean​ distance between objects ​as​ the ​base of its similarity metric​,​ ​this​ should be changed ​as​ appropriate.

使用t-SNE技术可以将高维数据投影到2维或3维进行可视化,使得在高维空间中相近点在低维空间中也相近。TensorBoard提供了t-SNE和PCA两种可视化技术。
最后的可视化结果就是本文最开始的部分已经给出。
相关代码

from tensorflow.contrib.tensorboard.plugins import projector 

# 在训练好词向量后获取embed_matrix
final_embed_matrix ​=​ sess​.​run​(​model​.​embed_matrix) 
# 创建一个tf.Variable来容纳embeddings,这里不能用constans,也不能用之前模型里定义的embed_matrix.
# 获取前500个最流行的单词
embedding_var = tf.Variable(final_embed_matrix[:500],name='embedding') 
sess.run(embedding_var.initializer) 
cOnfig= projector.ProjectorConfig() 
summary_writer = tf.summary.FileWriter(LOGDIR) 

# 向config添加embedding
embedding = config.embeddings.add()
embedding.tensor_name = embedding_var.name 

# link the embeddings to their metadata file. In this case, the file that contains 
# the 500 most popular words in our vocabulary 
embedding.metadata_path = LOGDIR + '/vocab_500.tsv' 

# save a configuration file that TensorBoard will read during startup 
projector.visualize_embeddings(summary_writer, config) 

# save our embedding 
saver_embed = tf.train.Saver([embedding_var]) saver_embed.save(sess, LOGDIR + '/skip-gram.ckpt', 1) 


推荐阅读
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 独家解析:深度学习泛化理论的破解之道与应用前景
    本文深入探讨了深度学习泛化理论的关键问题,通过分析现有研究和实践经验,揭示了泛化性能背后的核心机制。文章详细解析了泛化能力的影响因素,并提出了改进模型泛化性能的有效策略。此外,还展望了这些理论在实际应用中的广阔前景,为未来的研究和开发提供了宝贵的参考。 ... [详细]
  • 利用ZFS和Gluster实现分布式存储系统的高效迁移与应用
    本文探讨了在Ubuntu 18.04系统中利用ZFS和Gluster文件系统实现分布式存储系统的高效迁移与应用。通过详细的技术分析和实践案例,展示了这两种文件系统在数据迁移、高可用性和性能优化方面的优势,为分布式存储系统的部署和管理提供了宝贵的参考。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
  • 超分辨率技术的全球研究进展与应用现状综述
    本文综述了图像超分辨率(Super-Resolution, SR)技术在全球范围内的最新研究进展及其应用现状。超分辨率技术旨在从单幅或多幅低分辨率(Low-Resolution, LR)图像中恢复出高质量的高分辨率(High-Resolution, HR)图像。该技术在遥感、医疗成像、视频处理等多个领域展现出广泛的应用前景。文章详细分析了当前主流的超分辨率算法,包括基于传统方法和深度学习的方法,并探讨了其在实际应用中的优缺点及未来发展方向。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 最详尽的4K技术科普
    什么是4K?4K是一个分辨率的范畴,即40962160的像素分辨率,一般用于专业设备居多,目前家庭用的设备,如 ... [详细]
  • 在List和Set集合中存储Object类型的数据元素 ... [详细]
  • 如何在C#中配置组合框的背景颜色? ... [详细]
  • 计算机视觉领域介绍 | 自然语言驱动的跨模态行人重识别前沿技术综述(上篇)
    本文介绍了计算机视觉领域的最新进展,特别是自然语言驱动的跨模态行人重识别技术。上篇内容详细探讨了该领域的基础理论、关键技术及当前的研究热点,为读者提供了全面的概述。 ... [详细]
  • 如何使用mysql_nd:Python连接MySQL数据库的优雅指南
    无论是进行机器学习、Web开发还是爬虫项目,数据库操作都是必不可少的一环。本文将详细介绍如何使用Python通过 `mysql_nd` 库与 MySQL 数据库进行高效连接和数据交互。内容涵盖以下几个方面: ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
author-avatar
PrinceVince_820
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有